package pl.edu.mimuw.irs.core.model.analysis.subnet;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import pl.edu.mimuw.irs.core.model.analysis.GlobalElementsWorkflow;
import pl.edu.mimuw.irs.core.model.analysis.ResourcePlace;
import pl.edu.mimuw.irs.core.model.analysis.RolePlace;
import pl.edu.mimuw.irs.core.model.design.IRSNodeInterface;
import pl.edu.mimuw.irs.core.model.design.IRSResourceSet;
import pl.edu.mimuw.irs.core.model.design.IRSWorkflow;
import pl.edu.mimuw.irs.core.model.design.processing.Role;
import pl.edu.mimuw.irs.core.model.petrinet.Arc;
import pl.edu.mimuw.irs.core.model.petrinet.Transition;
import pl.edu.mimuw.irs.core.util.Position;

/**
 * @author Jakub Rauch
 * Created on: 2009-05-27
 */
public class ResourcesWorkflow extends GlobalElementsWorkflow {

	// *** Attributes
	
	private Map<IRSResourceSet, ResourceSetSubnet> resourceSetMap;
	public Map<IRSResourceSet, ResourceSetSubnet> getResourceSetMap() {
		if (this.resourceSetMap == null) resourceSetMap = 
			new LinkedHashMap<IRSResourceSet, ResourceSetSubnet>();
		return resourceSetMap;
	}
	public void setResourceSetMap(
			Map<IRSResourceSet, ResourceSetSubnet> resourceSetMap) {
		this.resourceSetMap = resourceSetMap;
	}
	
	// *** Constructors
	
	public ResourcesWorkflow(IRSWorkflow workflow) {
		super(workflow);
		
		Set<IRSResourceSet> resourceSetSet = getResourceSets(workflow.getRootPlace());
		Map<IRSResourceSet, ResourceSetSubnet> resourceSetMap = getResourceSetMap();
		
		for (IRSResourceSet resourceSet : resourceSetSet) {
			ResourceSetSubnet subnet = new ResourceSetSubnet(resourceSet);
			linkResourceSetSubnet(subnet);
			resourceSetMap.put(resourceSet, subnet);
		}
	}
	
	// *** Methods
	
	private Set<IRSResourceSet> getResourceSets(IRSNodeInterface node) {
		if (node instanceof IRSResourceSet) return Collections.singleton((IRSResourceSet)node);
		else {
			Set<IRSResourceSet> resourceSets = new HashSet<IRSResourceSet>();
			for (IRSNodeInterface child : node.getChildren()) {
				resourceSets.addAll(getResourceSets(child));
			}
			return resourceSets;
		}
	}
	
	private void linkResourceSetSubnet(ResourceSetSubnet subnet) {
		Transition initialize = getInitialize();
		Transition finalize = getFinalize();
		Position position = null;
		
		// Roles places and transitions
		Map<Role, Arc> initializeArcs = new HashMap<Role, Arc>();
		Map<Role, Arc> finalizeArcs = new HashMap<Role, Arc>();
		for (RolePlace place : subnet.getRolePlaces()) {
			Arc initializeArc = initializeArcs.get(place.getRole());
			Arc finalizeArc = finalizeArcs.get(place.getRole());
			// Always both exists or both do not exist (as well as the place).
			if (initializeArc == null || finalizeArc == null) {
				addPlace(place);
				initializeArc = new Arc(initialize, place);
				addArc(initializeArc);
				initializeArcs.put(place.getRole(), initializeArc);
				finalizeArc = new Arc(place, finalize);
				addArc(finalizeArc);
				finalizeArcs.put(place.getRole(), finalizeArc);
				if (position == null) position = new Position(60, 160);
				else position = new Position(position.getX(), position.getY() + 50);
				place.setPosition(position);
			} else {
				initializeArc.setWeight(initializeArc.getWeight() + 1);
				finalizeArc.setWeight(finalizeArc.getWeight() + 1);
			}
		}
		
		if (position == null) position = new Position(60, 160);
		else position = new Position(position.getX(), position.getY() + 50);
		
		// Resource places and trasitions
		for (ResourcePlace place : subnet.getResourcePlaces()) {
			addPlace(place);
			addArc(initialize, place);
			addArc(place, finalize);
			if (position == null) position = new Position(60, 160);
			else position = new Position(position.getX(), position.getY() + 50);
			place.setPosition(position);
		}
	}	
	
}
